package ru.yandex.api.money.util;

import java.io.*;
import java.net.*;

/**
 * Unitily class to simplify http requests
 * 
 * @author: Melnikov Ivan melnikov.ivan@gmail.com
 */
public class RequestBuilder {
	
	private static final String encoding = "UTF-8";
	private static final String amp = "&";
	
	private boolean first = true;
	
	private HttpURLConnection connection;
	private OutputStreamWriter writer;

	public RequestBuilder(String address) {
		try {
			URL url = new URL(address);
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset="+encoding);
			connection.setDoOutput(true);
			connection.setRequestMethod("POST");
			connection.setInstanceFollowRedirects(false);

		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public RequestBuilder auth(String accessToken) {
		connection.setRequestProperty("Authorization", "Bearer "+accessToken);
		return this;
	}
	
	public RequestBuilder addParam(String name, String value) {
		try {
			if (writer == null)
				try {
					OutputStream stream = connection.getOutputStream();
					writer = new OutputStreamWriter(stream, encoding);
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			
			if (!first)
				writer.write(amp);
			
			writer.write(name + "=" + URLEncoder.encode(value, encoding));
			first = false;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return this;
	}
	
	public RequestBuilder addParam(String name, int value) {
		return addParam(name, value+"");
	}
	
	public String redirect() {
		try {
			if (writer != null)
				writer.close();
			
			String content = asString(connection.getInputStream());

			String location = connection.getHeaderField("Location");
			if (location != null && !"".equals(location))
				return location;
			else 
				throw new RuntimeException("Failed to redirect: "+content);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public String build() {
		try {
			if (writer != null)
				writer.close();
			
			final int code = connection.getResponseCode();
			if (code != 200)
				processError(code);
			
			return asString(connection.getInputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	protected static void processError(final int code) {
		System.out.println("HTTP "+code);
		if (400 == code)
			throw new RuntimeException("Invalid request params");
		if (401 == code)
			throw new RuntimeException("Unauthorized");
		if (403 == code)
			throw new RuntimeException("Unsufficient scope");
	}
	
	public static String asString(InputStream stream) throws IOException {
		InputStreamReader reader = new InputStreamReader(stream);
		char[] arr = new char[8 * 1024]; // 8K at a time
		StringBuffer buf = new StringBuffer();
		int numChars;

		while ((numChars = reader.read(arr, 0, arr.length)) > 0) {
			buf.append(arr, 0, numChars);
		}

		return buf.toString();
	}
}